package top.ninwoo.utils.util.impl;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import top.ninwoo.utils.entity.ChainEntity;
import top.ninwoo.utils.entity.ChainType;
import top.ninwoo.utils.entity.TableType;
import top.ninwoo.utils.util.DockerUtils;
import top.ninwoo.utils.util.IptablesUtils;
import top.ninwoo.utils.util.Utils;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @Author joliu
 * @Description
 * @Date　Create in 上午11:42 2019/10/29
 */
@Utils
public class IptablesUtilsImpl implements IptablesUtils {

    private static final Logger LOG = LoggerFactory.getLogger(IptablesUtilsImpl.class);

    @Autowired
    DockerUtils dockerUtils;

    @Override
    public Map<String, List<ChainEntity>> showIptablesDetail(String containerId) {
        return showIptablesDetail(containerId, "filter");
    }

    @Override
    public Map<String, List<ChainEntity>> showIptablesDetail(String containerId, String type) {
        /**
         * Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
         *  pkts bytes target     prot opt in     out     source               destination
         *     0     0 DROP       all  --  *      *       10.1.100.3           0.0.0.0/0
         *
         * Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
         *  pkts bytes target     prot opt in     out     source               destination
         *
         * Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
         *  pkts bytes target     prot opt in     out     source               destination
         */
        Map<String, List<ChainEntity>> map = new HashMap<>();
        map.put("INPUT", new ArrayList<>());
        map.put("FORWARD", new ArrayList<>());
        map.put("OUTPUT", new ArrayList<>());
        map.put("PREROUTING", new ArrayList<>());
        map.put("POSTROUTING", new ArrayList<>());
        String cmd = "";
        switch (type) {
            case "filter":
                cmd = "iptables --lines -vnL";
                break;
            case "nat":
                cmd = "iptables -t nat --lines -vnL";
                break;
        }

        String result = dockerUtils.execInDocker(containerId, cmd.split(" "));
        String[] lines = result.split("\n");
        ChainEntity.Builder builder = ChainEntity.builder();
        String key = "";
        for (int i = 0; i < lines.length; i++) {
            if(lines[i].startsWith("Chain INPUT")) {
                builder = ChainEntity.builder().type(ChainType.INPUT);
                key = "INPUT";
                i++;
                continue;
            } else if(lines[i].startsWith("Chain FORWARD")) {
                builder = ChainEntity.builder().type(ChainType.FORWARD);
                key = "FORWARD";
                i++;
                continue;
            } else if(lines[i].startsWith("Chain OUTPUT")) {
                builder = ChainEntity.builder().type(ChainType.OUTPUT);
                key = "OUTPUT";
                i++;
                continue;
            }

            if("".equals(lines[i])) {
                continue;
            }


            String[] s = lines[i].replaceAll(" +", " ").trim().split(" ");
            ChainEntity chain;
            if(s.length >= 10) {
                chain = builder.id(Integer.parseInt(s[0]))
                        .pkts(Long.parseLong(s[1]))
                        .bytes(Long.parseLong(s[2]))
                        .target(s[3])
                        .prot(s[4])
                        .opt(s[5])
                        .in(s[6])
                        .out(s[7])
                        .source(s[8])
                        .destination(s[9])
                        .build();
                if(s.length > 10) {
                    StringBuilder more = new StringBuilder();
                    for (int j = 10; j < s.length ; j++) {
                        more.append(s[j]).append(" ");
                    }
                    chain.setMore(more.toString());
                }
                map.get(key).add(chain);
            }

        }
        return map;
    }

    @Override
    public String addIptable(String containerId, String kind, ChainType chainType, String source, String destination, String policy) {
        // TODO: 再简化些
        return basicCommand(containerId, null, kind, chainType, source, destination, policy);
    }

    @Override
    public String delIptable(String containerId, ChainType chainType, String source, String destination, String policy) {
        // 删除
        return basicCommand(containerId, null, "delete", chainType, source, destination, policy);
    }

    private String basicCommand(String containerId, TableType table, String kind, ChainType chainType, String source, String destination, String policy) {
        return basicCommand(containerId, table, kind, chainType, source, destination, policy, 0);
    }

    @Override
    public String delIptable(String containerId, TableType tableType, ChainType chainType, int lineNumber) {
        return basicCommand(containerId, null, "delete", chainType, "", "", "", lineNumber);
    }

    /**
     * 这是一个临时偷懒的借口
     * @param containerId
     * @param cmd
     * @return
     */
    @Override
    public String supperiseCmd(String containerId, String cmd) {
        return dockerUtils.execInDocker(containerId, cmd.split(" "));
    }

    /**
     * 修改table条目
     * @param containerId
     * @param chainType
     * @param source
     * @param destination
     * @param policy
     * @param lineNumber
     * @return
     */
    @Override
    public boolean modifyIptable(String containerId, ChainType chainType, String source, String destination, String policy, int lineNumber) {
        String cmd = buildCommand(TableType.filter, "modify", chainType, source, destination, policy, lineNumber);
        String s = dockerUtils.execInDocker(containerId, cmd.split(" "));
        if("".equals(s)) {
            return true;
        }
        return false;
    }

    /**
     * 清空iptables，这是一个很不安全的操作
     * @return
     */
    @Override
    public boolean flushIptables(String containerId, ChainType chainType) {
        String cmd = "iptables -F " + chainType;
        if("".equals(dockerUtils.execInDocker(containerId, cmd.split(" ")))) {
            return true;
        }
        return false;
    }

    /**
     * 基本的执行命令函数
     * @param containerId
     * @param table
     * @param kind
     * @param chainType
     * @param source
     * @param destination
     * @param policy
     * @param lineNumber
     * @return
     */
    public String basicCommand(String containerId, TableType table, String kind, ChainType chainType, String source, String destination, String policy, int lineNumber) {
        String cmd = buildCommand(table, kind, chainType, source, destination, policy, lineNumber);
        return dockerUtils.execInDocker(containerId, cmd.split(" "));
    }

    /**
     * 添加iptable项
     * 这里应该还可以提供一个更加通用的模块，这里暂时先不实现
     *  example: iptables -I INPUT -s 172.0.0.2 -j DROP
     * @param kind
     * @param chainType
     * @param source
     * @param destination
     * @param policy
     */
    public String buildCommand(TableType table, String kind, ChainType chainType, String source, String destination, String policy, int lineNumber) {
        // 构建iptables的命令
        String cmd = "iptables ";

        if(table != null) {
            switch (table) {
                case raw:
                    cmd += "-t filter ";
                    break;
                case filter:
                    cmd += "-t filter ";
                    break;
                default:
                    throw new RuntimeException("不支持的table[" + table + "]");
            }
        }

        switch (kind) {
            case "insert":
                cmd += "-I ";
                break;
            case "append":
                cmd += "-A ";
                break;
            case "delete":
                cmd += "-D ";
                break;
            case "modify":
                cmd += "-R ";
                break;
            default:
                throw new RuntimeException("不支持的操作");
        }

        cmd += chainType.toString() + " ";

        if(lineNumber > 0) {
            cmd += lineNumber + " ";
        }

        if(!"".equals(source)) {
            cmd += "-s " + source + " ";
        }
        if(!"".equals(destination)) {
            cmd += "-d " + destination + " ";
        }
        if(!"".equals(policy)) {
            cmd += "-j " + policy;
        }



        LOG.info("构建的cmd:[" + cmd + "]");
        return cmd;
        //return dockerUtils.execInDocker(containerId, cmd.split(" "));
    }

    // TODO: 差一个转发的实现
}
